/*
 * Copyright (c) 2011-2015. ShenZhen trendit Information Technology Co.,Ltd.
 *
 * All right reserved.
 *
 * This software is the confidential and proprietary
 * information of trendit Company of China.
 * ("Confidential Information"). You shall not disclose
 * such Confidential Information and shall use it only
 * in accordance with the terms of the contract agreement
 * you entered into with trendit inc.
 */

package com.trendit.classicpos.util;

import java.util.Arrays;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

public class Des3Coder {

    public final static String KEY_ALGORITHM = "DESede";

    public final static String CHIPER_ALGORITHM = "DESede/ECB/NoPadding";

    /**
     * 加密
     *
     * @param msg
     * @param key
     * @return
     */
    public static byte[] encrypt(byte[] msg, byte[] key) {
        byte[] des3Key = getKey(key);

        try {
            Cipher cipher = Cipher.getInstance(CHIPER_ALGORITHM);
            SecretKey secretKey = new SecretKeySpec(des3Key, KEY_ALGORITHM);
            cipher.init(Cipher.ENCRYPT_MODE, secretKey);
            byte[] encryptData = cipher.doFinal(fillGap(msg));
            if (encryptData == null || encryptData.length < msg.length) {
                return null;
            }
            byte[] finalEncryptData = new byte[msg.length];
            System.arraycopy(encryptData, 0, finalEncryptData, 0, finalEncryptData.length);
            return finalEncryptData;
        } catch (Exception e) {
            throw new RuntimeException("Error when encrypt key, ermsg: " + e.getMessage(), e);
        }
    }

    /**
     * 解密
     *
     * @param msg
     * @param key
     * @return
     */
    public static byte[] decrypt(byte[] msg, byte[] key) {
        byte[] des3Key = getKey(key);
        try {
            byte[] tempMsg;
            if (msg.length < key.length) {
                tempMsg = new byte[key.length];
                Arrays.fill(tempMsg, (byte) 0x00);
                System.arraycopy(msg, 0, tempMsg, 0, msg.length);
            } else {
                tempMsg = new byte[msg.length];
                System.arraycopy(msg, 0, tempMsg, 0, tempMsg.length);
            }

            Cipher cipher = Cipher.getInstance(CHIPER_ALGORITHM);
            SecretKey secretKey = new SecretKeySpec(des3Key, KEY_ALGORITHM);
            cipher.init(Cipher.DECRYPT_MODE, secretKey);
            byte[] decryptData = removeGap(cipher.doFinal(tempMsg));
            if (decryptData == null || decryptData.length < tempMsg.length) {
                return null;
            }
            byte[] finalDecryptData = new byte[msg.length];
            System.arraycopy(decryptData, 0, finalDecryptData, 0, finalDecryptData.length);
            return finalDecryptData;
        } catch (Exception e) {

            throw new RuntimeException("Error when drcrypt key, ermsg: " + e.getMessage(), e);
        }

    }

    /**
     * 得到3Deskey
     *
     * @param key
     * @return
     */
    private static byte[] getKey(byte[] key) {
        if (key.length == 24) {
            return key;
        }
        if (key.length != 16) {
            throw new IllegalArgumentException(" key length is not 16 bytes.");
        }
        byte[] des3Key = new byte[24];
        System.arraycopy(key, 0, des3Key, 0, 16);
        System.arraycopy(key, 0, des3Key, 16, 8);
        return des3Key;
    }

    /**
     * 补位操作
     *
     * @param srcBytes
     * @return
     */
    public static byte[] fillGap(byte[] srcBytes) {
//		try {
//			byte[] destBytes;
//			int len = srcBytes.length;
//			int total = len;
//			if(len%8!=0){
//				total = (len/8 + 1) * 8;
//			}
//			if(total==len){
//				destBytes = srcBytes;
//			}
//			
//			destBytes = new byte[total];
//			System.arraycopy(srcBytes, 0, destBytes, 0, len);
//			for(int i=len ; i<total ; i++){
//				destBytes[i] = (byte)0x00;
//			}
//			
//			return destBytes;
//		} catch (Exception e) {
//			throw new RuntimeException(" Error when msg fill gap "+ e.getMessage(), e);
//		}
        try {
            int len = srcBytes.length;
            int total = (len / 8 + 1) * 8;

            byte[] destBytes = new byte[total];
            System.arraycopy(srcBytes, 0, destBytes, 0, len);
            if (total - len == 1) {
                destBytes[len] = (byte) 0x80;
            } else {
                for (int i = len; i < total; i++) {
                    if (i == len) {
                        destBytes[i] = (byte) 0x80;
                    } else {
                        destBytes[i] = (byte) 0x00;
                    }

                }
            }
            return destBytes;
        } catch (Exception e) {
            throw new RuntimeException(" Error when msg fill gap " + e.getMessage(), e);
        }
    }

    /**
     * 移位操作
     *
     * @param srcBytes
     * @return
     */
    public static byte[] removeGap(byte[] srcBytes) {
//		byte[] desBytes;
//		try {
//			int len = srcBytes.length;
//			int pos = 0;
//			for(int i=len-1;i>=len-9;i--){
//				if(srcBytes[i]!=0){
//					pos = i;
//					break;
//				}
//			}
//			if(pos ==0){
//				desBytes = srcBytes;
//			}else{
//				desBytes = new byte[pos+1];
//				System.arraycopy(srcBytes, 0, desBytes, 0, pos+1);
//			}
//			return desBytes;
//		} catch (Exception e) {
//			throw new RuntimeException(" Error when msg remove gap "+ e.getMessage(), e);
//		}
        byte[] desBytes;
        try {
            int len = srcBytes.length;
            int pos = 0;
            for (int i = len - 1; i >= len - 9; i--) {
                if (srcBytes[i] == -128) {
                    pos = i;
                    break;
                }
            }
            if (pos == 0) {
                desBytes = srcBytes;
            } else {
                desBytes = new byte[pos];
                System.arraycopy(srcBytes, 0, desBytes, 0, pos);
            }
            return desBytes;
        } catch (Exception e) {
            throw new RuntimeException(" Error when msg remove gap " + e.getMessage(), e);
        }

    }


}
